type Empty = null | undefined;
type RuleGroupMode = "struct" | "some" | "array";
type RuleValue = boolean | number | string | Date | Array<string> | any;
type ValueSource = "value" | "field" | "func" | "const";
type AnyObject = object;

type JsonItem = JsonGroup|JsonAnyRule;
type JsonAnyRule = JsonRule|JsonRuleGroup|JsonRuleGroupExt;
type JsonRuleGroup = {
  type: "rule_group",
  id?: string,
  children1?: {[id: string]: JsonRule} | [JsonRule],
  properties?: RuleGroupProperties
}
type JsonRuleGroupExt = {
  type: "rule_group",
  id?: string,
  children1?: {[id: string]: JsonRule} | [JsonRule],
  properties?: RuleGroupExtProperties
}
interface BasicItemProperties {
  isLocked?: boolean,
}
interface RuleGroupProperties extends BasicItemProperties {
  field: string | Empty,
  mode?: RuleGroupMode,
}
interface RuleProperties extends BasicItemProperties {
  field: string | Empty,
  operator: string | Empty,
  value: Array<RuleValue>,
  valueSrc?: Array<ValueSource>,
  valueType?: Array<string>,
  valueError?: Array<string>,
  operatorOptions?: AnyObject,
}
interface RuleGroupExtProperties extends RuleProperties {
  mode: RuleGroupMode,
}
type JsonRule = {
  type: "rule",
  id?: string,
  properties: RuleProperties,
}
type JsonGroup = {
  type: "group",
  id?: string,
  // tip: if got array, it will be converted to immutable ordered map in `_addChildren1`
  children1?: {[id: string]: JsonItem} | [JsonItem],
  properties?: GroupProperties
}
interface GroupProperties extends BasicItemProperties {
  conjunction: string,
  not?: boolean,
}
type JsonCaseGroup = {
  type: "case_group",
  id?: string,
  children1?: {[id: string]: JsonGroup} | [JsonGroup],
  properties?: BasicItemProperties
};
type JsonSwitchGroup = {
  type: "switch_group",
  id?: string,
  children1?: {[id: string]: JsonCaseGroup} | [JsonCaseGroup],
  properties?: BasicItemProperties
};

export type JsonTree = JsonGroup|JsonSwitchGroup;